package fem2.gui.src;

import math2.FunctionRnToR;
import math2.NullFunctionRnToR;
import vtk.vtkCellArray;
import vtk.vtkDoubleArray;
import vtk.vtkPoints;
import vtk.vtkPolyData;
import fem2.Edge;
import fem2.Element;
import fem2.FieldInfo;

public class HofemCurvesSource extends HofemSource {

	private static final int NP = 20;
	private double[] vdnr_ = { 0, 1 };

	@Override
	protected void doExecute() {
		int n = modelHolder_.getModel().getMesh().countEdges();
		vtkPolyData outPD = GetPolyDataOutput();
		vtkPoints outPts = new vtkPoints();
		vtkCellArray outLines = new vtkCellArray();
		vtkDoubleArray da = null;

		outPD.SetPoints(outPts);
		outPD.SetLines(outLines);

		if (modelHolder_.solutionAvailable()) {
			da = new vtkDoubleArray();
			da.SetNumberOfComponents(3);
			outPD.GetPointData().SetVectors(da);
		}

		for (int i = 0; i < n; i++) {
			Edge edge = modelHolder_.getModel().getMesh().getEdge(i);

			insertCurvePoints(edge, outPts, outLines, da);
		}
	}

	private FunctionRnToR[] getU(Edge edge) {
		NullFunctionRnToR nf = new NullFunctionRnToR();
		int d = modelHolder_.getModel().getMesh().countFields();

		if (d > 0) {
			FunctionRnToR[] u = { nf, nf, nf };
			Element element = modelHolder_.getModel().getElement(0);
			for (int i = 0; i < d; i++) {
				int id = element.getFieldId(i);
				if (id == FieldInfo.U1) {
					u[0] = edge.getSolution(i);
				} else if (id == FieldInfo.U2) {
					u[1] = edge.getSolution(i);
				} else if (id == FieldInfo.U3) {
					u[2] = edge.getSolution(i);
				}
			}
			return u;
		}
		return new FunctionRnToR[] { nf, nf, nf };

	}

	public double[] getVectorDataNormRange() {
		return vdnr_;
	}

	private void insertCurvePoints(Edge edge, vtkPoints pts, vtkCellArray lines, vtkDoubleArray da) {
		double dxi = 2.0 / (NP - 1);
		FunctionRnToR[] u = null;
		double u1, u2, u3, un;
		double maxU = 0;

		if (da != null) {
			u = getU(edge);
		}

		lines.InsertNextCell(NP);
		for (int i = 0; i < NP; i++) {
			double xi = -1 + i * dxi;
			double[] p = edge.valueAt(xi);

			if (da != null) {
				assert u != null;
				u1 = u[0].valueAt(xi);
				u2 = u[1].valueAt(xi);
				u3 = u[2].valueAt(xi);
				un = Math.sqrt(u1 * u1 + u2 * u2 + u3 * u3);

				if (un > maxU) {
					maxU = un;
				}
				da.InsertNextTuple3(u1, u2, u3);
			}
			lines.InsertCellPoint(pts.InsertNextPoint(p[0], p[1], 0));
		}
		vdnr_ = new double[] { 0, maxU };
	}

	@Override
	protected void modelChanged() {
		Modified();
	}

	@Override
	protected void solutionDataChanged() {
		Modified();
	}
}
